/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GraphDraw;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.io.IOException;
import org.mcavallo.opencloud.Cloud;
import org.mcavallo.opencloud.Tag;
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Calendar;
import java.sql.*;
import org.jfree.data.time.*;
import org.jfree.data.xy.*;
import org.jfree.data.category.*;
import org.jfree.data.general.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.renderer.*;
import org.jfree.chart.renderer.category.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.chart.servlet.*;

/**
 *
 * @author Riz
 */
public class GraphDraw {
    
    private enum TimeStep {MONTH(1), QUARTER(3), SEMESTER(6), YEAR(12);
    public final int value;
    private TimeStep(int val){value = val;}
    }

    private TimeStep timeStep;
    private ArrayList<String> institutions;
    private GregorianCalendar startDate;
    private GregorianCalendar endDate;
    private int [][] papers;
    private int [] totalPapers;
    private ChartTheme chartTheme;
    private Cloud cloud;
    private Cloud cloud1;
    private Cloud cloud2;
    private boolean isAllInstitutions;

    public GraphDraw (String university1, String university2, int startYear, int endYear, int startMonth, int endMonth)
    {
        endMonth--;
        institutions = new ArrayList<String>();
        institutions.add(university1);
        institutions.add(university2);
        this.startDate = new GregorianCalendar();
        startDate.set(startYear, startMonth, 1);
        this.endDate = new GregorianCalendar();
        endDate.set(endMonth==12?endYear+1:endYear, endMonth==12?1:endMonth+1, 1);
        papers = new int[2][endMonth - startMonth + 1 + (endYear - startYear)*12];
        totalPapers = new int[0];
        isAllInstitutions = false;
        setupCloud();
        createTheme();
        retrieveData();
    }

    public GraphDraw (String university1, int startYear, int endYear, int startMonth, int endMonth)
    {
        endMonth--;
        institutions = new ArrayList<String>();
        institutions.add(university1);
        this.startDate = new GregorianCalendar();
        startDate.set(startYear, startMonth, 1);
        this.endDate = new GregorianCalendar();
        endDate.set(endMonth==12?endYear+1:endYear, endMonth==12?1:endMonth+1, 1);
        papers = new int[1][endMonth - startMonth + 1 + (endYear - startYear)*12];
        totalPapers = new int[0];
        isAllInstitutions = false;
        setupCloud();
        createTheme();
        retrieveData();
    }

    public GraphDraw (int startYear, int endYear, int startMonth, int endMonth)
    {
        endMonth--;
        institutions = new ArrayList<String>();
        this.startDate = new GregorianCalendar();
        startDate.set(startYear, startMonth, 1);
        this.endDate = new GregorianCalendar();
        endDate.set(endMonth==12?endYear+1:endYear, endMonth==12?1:endMonth+1, 1);
        papers = new int[1][endMonth - startMonth + 1 + (endYear - startYear)*12];
        totalPapers = new int[50]; // 11 institutions
        isAllInstitutions = true;
        setupCloud();
        createTheme();
        retrieveData();
    }

    /*private int calculateTimeStep(int startYear, int endYear, int startMonth, int endMonth)
    {
        int numMonths = endMonth - startMonth + (endYear - startYear)*12;
        if (numMonths > 12  && numMonths < 37)
        {
            timeStep = TimeStep.QUARTER;
            return (int)Math.ceil(numMonths/3.0);
        }
        else if (numMonths > 36 && numMonths < 73)
        {
            timeStep = TimeStep.SEMESTER;
            return (int)Math.ceil(numMonths/6.0);
        }
        else if (numMonths > 72)
        {
            timeStep = TimeStep.YEAR;
            return (int)Math.ceil(numMonths/12.0);
        }
        else
        {
            timeStep = TimeStep.MONTH;
            return numMonths;
        }
    }*/

    private void createTheme()
    {
        //chartTheme = StandardChartTheme.createDarknessTheme();
        //ChartFactory.setChartTheme(chartTheme);
    }

    private void setupCloud()
    {
        cloud = new Cloud();
        cloud.setMaxWeight(36.0);
        cloud.setMaxTagsToDisplay(20);
        cloud.setTagCase(Cloud.Case.PRESERVE_CASE);
        cloud.setMinWeight(6.0);
        cloud1 = new Cloud();
        cloud1.setMaxWeight(36.0);
        cloud1.setMaxTagsToDisplay(20);
        cloud1.setTagCase(Cloud.Case.PRESERVE_CASE);
        cloud1.setMinWeight(6.0);
        cloud2 = new Cloud();
        cloud2.setMaxWeight(36.0);
        cloud2.setMaxTagsToDisplay(20);
        cloud2.setTagCase(Cloud.Case.PRESERVE_CASE);
        cloud2.setMinWeight(6.0);
    }

    private void retrieveData()
    {   
        try
        {
            String startDateString = "\"" + startDate.get(Calendar.YEAR) + "-" + (startDate.get(Calendar.MONTH)+1) + "-1 00:00:00\"";
            String endDateString = "\"" + endDate.get(Calendar.YEAR) + "-" + (endDate.get(Calendar.MONTH)+1) + "-1 00:00:00\"";
            RepositoryHarvester.DatabaseConnection connection = new RepositoryHarvester.DatabaseConnection(new RepositoryHarvester.HarvestConfiguration());
            if (connection.Connect())
            {
                if (isAllInstitutions)
                {
                    ResultSet resultSet = connection.doQuery("SELECT Institution, Date_Created, Subjects FROM Archive WHERE Date_Created >= " + startDateString + " AND Date_Created < " + endDateString + " ORDER BY Institution");
                    String lastInstitution = "";
                    int index = -1;
                    while(resultSet.next())
                    {
                        String inst = resultSet.getString("Institution");
                        if (!inst.equals(lastInstitution))
                        {
                            lastInstitution = inst;
                            institutions.add(inst);
                            index++;
                        }
                        Timestamp timestamp = resultSet.getTimestamp("Date_Created");
                        String timestampString = timestamp.toString();
                        int month = Integer.parseInt(timestampString.substring(5,7));
                        int year = Integer.parseInt(timestampString.substring(0,4));
                        int paperIndex = (month - (startDate.get(Calendar.MONTH)+1) + (year - startDate.get(Calendar.YEAR))*12);
                        papers[0][paperIndex]++;
                        totalPapers[index]++;
                        String [] subjects = resultSet.getString("Subjects").split(";");
                        for (int i = 0; i < subjects.length; i++)
                            cloud.addTag(subjects[i].trim());
                    }
                }
                else
                {
                    ResultSet resultSet1 = connection.doQuery("SELECT Date_Created, Subjects FROM Archive WHERE Date_Created >= " + startDateString + " AND Date_Created < " + endDateString + " AND Institution = \"" + institutions.get(0) + "\"");
                    while(resultSet1.next())
                    {
                        Timestamp timestamp = resultSet1.getTimestamp("Date_Created");
                        String timestampString = timestamp.toString();
                        int month = Integer.parseInt(timestampString.substring(5,7));
                        int year = Integer.parseInt(timestampString.substring(0,4));
                        int paperIndex = (month - (startDate.get(Calendar.MONTH)+1) + (year - startDate.get(Calendar.YEAR))*12);
                        //System.err.println (endDateString +" " + endDate);
                        papers[0][paperIndex]++;
                        String [] subjects = resultSet1.getString("Subjects").split(";");
                        for (int i = 0; i < subjects.length; i++)
                            cloud1.addTag(subjects[i].trim());
                    }
                    if (institutions.size() == 2)
                    {
                        ResultSet resultSet2 = connection.doQuery("SELECT Date_Created, Subjects FROM Archive WHERE Date_Created >= " + startDateString + " AND Date_Created < " + endDateString + " AND Institution = \"" + institutions.get(1) + "\"");
                        while(resultSet2.next())
                        {
                            Timestamp timestamp = resultSet2.getTimestamp("Date_Created");
                            String timestampString = timestamp.toString();
                            int month = Integer.parseInt(timestampString.substring(5,7));
                            int year = Integer.parseInt(timestampString.substring(0,4));
                            int paperIndex = (month - (startDate.get(Calendar.MONTH)+1) + (year - startDate.get(Calendar.YEAR))*12);
                            papers[1][paperIndex]++;
                            String [] subjects = resultSet2.getString("Subjects").split(";");
                            for (int i = 0; i < subjects.length; i++)
                                cloud2.addTag(subjects[i].trim());
                        }
                    }
                }
                connection.Disconnect();
            }
            
        }
        catch (SQLException e){}
    }

    private XYDataset createLineGraphDataset(boolean cumulative)
    {
        TimeSeriesCollection dataset = new TimeSeriesCollection();
        TimeSeries series1 = new TimeSeries(isAllInstitutions?"All universities in database":institutions.get(0));
        Month current = new Month(startDate.get(Calendar.MONTH)+1, startDate.get(Calendar.YEAR));
        int sum = 0;
        for (int i = 0; i < papers[0].length; i++)
        {
            series1.add(current, papers[0][i] + sum);
            if (cumulative)
                sum += papers[0][i];
            current = (Month)current.next();
        }
        dataset.addSeries(series1);
        sum = 0;
        if (institutions.size()==2 && !isAllInstitutions)
        {
            TimeSeries series2 = new TimeSeries(institutions.get(1));
            current = new Month(startDate.get(Calendar.MONTH)+1, startDate.get(Calendar.YEAR));
            for (int i = 0; i < papers[0].length; i++)
            {
                series2.add(current, papers[1][i] + sum);
                if (cumulative)
                    sum += papers[1][i];
                current = (Month)current.next();
            }
            dataset.addSeries(series2);
        }
        return dataset;
    }

    private PieDataset createPieChartDataset()
    {
        DefaultPieDataset dataset = new DefaultPieDataset();
        double total = 0;
        for (int i = 0; i < totalPapers.length;i++)
            total += totalPapers[i];
        for (int i = 0; i < institutions.size();i++)
            dataset.setValue(institutions.get(i), totalPapers[i]/total*100);
        return dataset;
    }

    private IntervalXYDataset createHistogramDataset()
    {
        TimePeriodValuesCollection dataset = new TimePeriodValuesCollection();
        Month current = new Month(startDate.get(Calendar.MONTH)+1, startDate.get(Calendar.YEAR));
        if (isAllInstitutions)
        {
            TimePeriodValues values = new TimePeriodValues("All universities");
            for (int i = 0; i < papers[0].length; i++)
            {
                values.add(current, papers[0][i]);
                current = (Month)current.next();
            }
            dataset.addSeries(values);
        }
        else
        {
            for (int i = 0; i < papers.length; i++)
            {
                TimePeriodValues values = new TimePeriodValues(institutions.get(i));
                current = new Month(startDate.get(Calendar.MONTH)+1, startDate.get(Calendar.YEAR));
                for (int j = 0; j < papers[0].length; j++)
                {
                    values.add(current,papers[i][j]);
                    current = (Month)current.next();
                }
                dataset.addSeries(values);
            }
        }
        return dataset;
    }

    public String createLineChart(javax.servlet.http.HttpSession session)
    {
        JFreeChart chart = ChartFactory.createTimeSeriesChart("Papers uploaded by universities", "Time", "Number of papers", createLineGraphDataset(false), true, true, false);
        ServletUtilities.setTempFilePrefix("LineChart");
        return publishChart(chart, 600, 300, session);
    }

    public String createCumulativeLineChart(javax.servlet.http.HttpSession session)
    {
        JFreeChart chart = ChartFactory.createTimeSeriesChart("Cumulative papers uploaded by universities", "Time", "Number of papers", createLineGraphDataset(true), true, true, false);
        ServletUtilities.setTempFilePrefix("CumLineChart");
        return publishChart(chart, 600, 300, session);
    }

    public String createPieChart(javax.servlet.http.HttpSession session)
    {
        JFreeChart chart = ChartFactory.createPieChart("Paper contributions from universities", createPieChartDataset(), true, true, false);
        ServletUtilities.setTempFilePrefix("PieChart");
        return publishChart(chart, 400,400, session);
    }

    public String createHistogram(javax.servlet.http.HttpSession session)
    {
        JFreeChart chart = ChartFactory.createHistogram("Papers uploaded by universities", "Time" , "Number of papers", createHistogramDataset(), PlotOrientation.VERTICAL, true, true, false);
        XYPlot plot = chart.getXYPlot();
        ClusteredXYBarRenderer renderer = new ClusteredXYBarRenderer();
        renderer.setShadowVisible(false);
        renderer.setDrawBarOutline(false);
         GradientPaint gp1 = new GradientPaint(
            0.0f, 0.0f, Color.blue,
            0.0f, 0.0f, new Color(0, 0, 64)
        );
        GradientPaint gp0 = new GradientPaint(
            0.0f, 0.0f, Color.red,
            0.0f, 0.0f, new Color(64, 0, 0)
        );
        renderer.setSeriesPaint(0, gp0);
        renderer.setSeriesPaint(1, gp1);
        StandardXYBarPainter painter = new StandardXYBarPainter();
        renderer.setBarPainter(painter);
        plot.setRenderer(renderer);
        ValueAxis val = plot.getDomainAxis();
        val.setTickLabelsVisible(false);
        ServletUtilities.setTempFilePrefix("Histogram");
        return publishChart(chart, 600, 300, session);
    }

    private String publishChart(JFreeChart chart, int width, int height, javax.servlet.http.HttpSession session)
    {
        try {return ServletUtilities.saveChartAsJPEG(chart, width, height, session);}
        catch (IOException e) {return "";}
    }

    private String generateCloudHTML(Cloud cl)
    {
        String html = "<div>";
        List<Tag> tags = cl.tags();
        ListIterator<Tag> it = tags.listIterator();
        while (it.hasNext())
        {
            Tag tag = it.next();
            html += "<font color=\"teal\" face=\"Calibri\" size=\"" + Math.round(tag.getWeight()/38*7) + "\">" + tag.getName() + "</font>&nbsp&nbsp&nbsp";
        }
        html += "</div>";
        return html;
    }

    public String getCloudHTML()
    {
        return generateCloudHTML(cloud);
    }

    public String getCloud1HTML()
    {
        return generateCloudHTML(cloud1);
    }

    public String getCloud2HTML()
    {
        return generateCloudHTML(cloud2);
    }
}
